#!/usr/local/bin/python
# -*- coding: utf-8 -*-

import logging, traceback, time, copy
from tornado.escape import json_encode, json_decode

import Queue, threading

import log, const
from mysqlHelper import mysql
from util import *
from user import *

logger = logging.getLogger(__name__)


class HallOfFameManager(util.SingleClass):
    '''名人堂管理器'''

    s_map_order_by_exp_key_uid_girl = {}     #{uid:order}      根据经验排序队列
    s_map_order_by_exp_key_uid_boy = {}      #{uid:order}      根据经验排序队列
    s_map_order_by_exp_key_order_girl = {}   #{order:userClientDict}
    s_map_order_by_exp_key_order_boy = {}    #{order:userClientDict}  
    s_list_order_by_exp_userinfo_girl = []   #[userClientDict]
    s_list_order_by_exp_userinfo_boy = []    #[userClientDict]
    
    s_map_order_by_charm_key_uid_girl = {}     #{uid:order}      根据魅力排序队列
    s_map_order_by_charm_key_uid_boy = {}      #{uid:order}      根据魅力排序队列
    s_map_order_by_charm_key_order_girl = {}   #{order:userClientDict}
    s_map_order_by_charm_key_order_boy = {}    #{order:userClientDict}  
    s_list_order_by_charm_userinfo_girl = []   #[userClientDict]
    s_list_order_by_charm_userinfo_boy = []    #[userClientDict]
    
    s_time_pre_exec = time.time()                       #上一次执行时间(秒)
    s_time_next_exec = time.time()                      #下一次执行时间(秒)
    s_time_step = const.Config_hall_of_fame_time_step   #执行时间间隔(秒)
    s_max_count = const.Config_hall_of_fame_max_count   #保存最多人数

    s_lock = threading.RLock()          #锁
    
    def __init__(self):
        pass

    def getUIDListExt(self, parmsType="exp", parmsSex=0, tmpCount=4):
        '''获取某项排序的UID列表[uid, uid]'''
        HallOfFameManager.s_lock.acquire()
        try:
            tmpResurtList = []
            tmpUserClientDictList = self._getClientDictListBySex(parmsType, parmsSex)  #{uid:order}  
            tmpList = util.getRandomFromList(tmpUserClientDictList, 100) #随机获取100个，
            iIndex = 0
            for tmpUserClientDict in tmpList:      # 从20个中获取符合条件的
                if iIndex >= tmpCount:
                    break
                if not isinstance(tmpUserClientDict, dict):
                    continue
                tmpUID = tmpUserClientDict.get("uid")
                tmpStrDay = tmpUserClientDict.get("last_login_time")
                if tmpUID and tmpStrDay and util.isDayDistance(tmpStrDay, 3):   #用户是否之日之内有登录:
                    iIndex += 1
                    util.inserList(tmpResurtList, tmpUID)
            return tmpResurtList
        finally:
            HallOfFameManager.s_lock.release() #解锁            
            
    
    def getTimePreExec(self):
        '''上一次执行时间(秒)'''
        HallOfFameManager.s_lock.acquire() 
        tmpVal = HallOfFameManager.s_time_pre_exec 
        HallOfFameManager.s_lock.release()
        return int(tmpVal)

    def setTimePreExec(self, val):
        '''上一次执行时间(秒)'''
        HallOfFameManager.s_lock.acquire()
        HallOfFameManager.s_time_pre_exec = val
        HallOfFameManager.s_lock.release()
        
    def _setTimePreExecNoLock(self, val):
        '''上一次执行时间(秒)'''
        HallOfFameManager.s_time_pre_exec = val
            
    def getTimeStep(self):
        '''执行时间间隔(秒)''' 
        HallOfFameManager.s_lock.acquire()
        tmpVal = HallOfFameManager.s_time_step 
        HallOfFameManager.s_lock.release()
        return int(tmpVal)

    def setTimeStep(self, val):
        '''执行时间间隔(秒)''' 
        HallOfFameManager.s_lock.acquire()
        HallOfFameManager.s_time_step = val 
        HallOfFameManager.s_lock.release()            
    
    def getTimeNextExec(self):
        '''下一次执行时间(秒)''' 
        HallOfFameManager.s_lock.acquire()
        tmpVal = HallOfFameManager.s_time_next_exec 
        HallOfFameManager.s_lock.release()
        return int(tmpVal)

    def _setTimeNextExecExtNoLock(self):  
        '''设置下一次执行时间(秒)  上次时间+时间步长'''
        HallOfFameManager.s_time_next_exec = HallOfFameManager.s_time_pre_exec + HallOfFameManager.s_time_step  
            
    def setTimeNextExec(self, val):
        '''设置下一次执行时间(秒) ''' 
        HallOfFameManager.s_lock.acquire()
        HallOfFameManager.s_time_next_exec = val 
        HallOfFameManager.s_lock.release()

    def getMaxCount(self):
        '''最大数量''' 
        HallOfFameManager.s_lock.acquire()
        tmpVal = HallOfFameManager.s_max_count 
        HallOfFameManager.s_lock.release()
        return tmpVal

    def setMaxCount(self, val):
        '''最大数量'''
        HallOfFameManager.s_lock.acquire()
        HallOfFameManager.s_max_count = val 
        HallOfFameManager.s_lock.release()   

    def getTotal(self, parmsType="exp", parmsSex=0):
        '''获取某项排序的人数'''
        HallOfFameManager.s_lock.acquire()
        try:
            return len(self._getMapBySex(parmsType, parmsSex))
        finally:
            HallOfFameManager.s_lock.release() #解锁            

    def _updateUserInfo_hidden_love_me_size(self, uid, tmpOrder, parmsType="exp", parmsSex=0):
        '''给内存排名内的某用户   粉丝数+1'''
        tmpOrderMap = self._getMapOrderUserBySex(parmsType, parmsSex)
        tmpClientDict = tmpOrderMap.get(tmpOrder)
        if tmpClientDict:
            tmpSize = tmpClientDict.get("hidden_love_me_size", 0) + 1
            tmpClientDict["hidden_love_me_size"] = tmpSize
    
    def addUserInfoHiddenLoveMeSize(self, uid, parmsSex=0):
        '''给内存排名内的某用户   粉丝数+1'''
        tmpOrder_exp = self.getOrderByUID(uid, "exp", parmsSex)
        tmpOrder_charm = self.getOrderByUID(uid, "charm", parmsSex)
        
        HallOfFameManager.s_lock.acquire()
        try:
            self._updateUserInfo_hidden_love_me_size(uid, tmpOrder_exp, "exp", parmsSex)
            self._updateUserInfo_hidden_love_me_size(uid, tmpOrder_charm, "charm", parmsSex)
        finally:
            HallOfFameManager.s_lock.release() #解锁             
            

    def _getListBySex(self, parmsType="exp", parmsSex=0):
        tmpList = []
        if parmsSex == 0: #女
            if parmsType == "exp":
                tmpList = HallOfFameManager.s_list_order_by_exp_userinfo_girl
            else:
                tmpList = HallOfFameManager.s_list_order_by_charm_userinfo_girl
        else:
            if parmsType == "exp":
                tmpList = HallOfFameManager.s_list_order_by_exp_userinfo_boy
            else:
                tmpList = HallOfFameManager.s_list_order_by_charm_userinfo_boy
        return tmpList
    
    def _getMapBySex(self, parmsType="exp", parmsSex=0):
        '''排序map {uid:order}'''
        tmpMap = {}
        if parmsSex == 0: #女
            if parmsType == "exp":
                tmpMap = HallOfFameManager.s_map_order_by_exp_key_uid_girl
            else:
                tmpMap = HallOfFameManager.s_map_order_by_charm_key_uid_girl
        else:
            if parmsType == "exp":
                tmpMap = HallOfFameManager.s_map_order_by_exp_key_uid_boy
            else:
                tmpMap = HallOfFameManager.s_map_order_by_charm_key_uid_boy
        return tmpMap
    
    
    def _getClientDictListBySex(self, parmsType="exp", parmsSex=0):
        '''获取队列'''
        tmpList = []
        if parmsSex == 0: #女
            if parmsType == "exp":
                tmpList = HallOfFameManager.s_list_order_by_exp_userinfo_girl   #[userClientDict]
            else:
                tmpList = HallOfFameManager.s_list_order_by_charm_userinfo_girl   #[userClientDict]
        else:
            if parmsType == "exp":
                tmpList = HallOfFameManager.s_list_order_by_exp_userinfo_boy    #[userClientDict]
            else:
                tmpList = HallOfFameManager.s_list_order_by_charm_userinfo_boy    #[userClientDict]
        return tmpList
    
    

    def _getMapOrderUserBySex(self, parmsType="exp", parmsSex=0):
        '''排序map {order:clientUserDict}'''
        tmpMap = {}
        if parmsSex == 0: #女
            if parmsType == "exp":
                tmpMap = HallOfFameManager.s_map_order_by_charm_key_order_girl
            else:
                tmpMap = HallOfFameManager.s_map_order_by_charm_key_order_girl
        else:
            if parmsType == "exp":
                tmpMap = HallOfFameManager.s_map_order_by_exp_key_order_boy
            else:
                tmpMap = HallOfFameManager.s_map_order_by_charm_key_order_boy
        return tmpMap

    def getOrderList(self, parmsOrderBegin, parmsOrderEnd, parmsType="exp", parmsSex=0):
        '''获取列表[infoDict]'''    
        tmpList = []    
        iBegin = max(parmsOrderBegin - 1, 0)
        
        if parmsOrderEnd < iBegin:
            parmsOrderEnd = iBegin + 1
        iEnd = parmsOrderEnd
            
        if parmsType not in ["exp", "charm"]:
            parmsType = "exp"
        
        HallOfFameManager.s_lock.acquire()  #加锁
        try:
            tmpList = copy.deepcopy(self._getListBySex(parmsType, parmsSex)[iBegin:iEnd]) #deepcopy
        finally:
            HallOfFameManager.s_lock.release() #解锁
        
        return tmpList
        
    def getOrderByUID(self, uid, parmsType="exp", parmsSex=0):
        '''获取某人的排名'''
        HallOfFameManager.s_lock.acquire()  #加锁
        try:
            tmpMap = self._getMapBySex(parmsType, parmsSex)
            return tmpMap.get(uid, len(tmpMap)+1)     
        finally:
            HallOfFameManager.s_lock.release() #解锁

    def enter(self, tmpUser, place="hall_or_fame"): 
        '''进名人堂'''
        if tmpUser:            
            uid = tmpUser.getUID()
            socket_id = tmpUser.getSocketID()
            log.print_debug(logger, "HallOfFameManager enter, socket_id:[%s], uid:[%s]" % (socket_id, uid))
            
            tmpUser.setCurrentPlace(place) #所在模块
    
    def execOrder(self):
        '''执行排序'''
        tmpBeginTime = time.time()
        log.print_debug(logger, "HallOfFameManager execOrder begin...beginTime[%s]----------" % tmpBeginTime)

        try:
            #经验排序
            tmp_map_order_key_uid_for_exp_girl, tmp_map_order_key_order_for_exp_girl, tmp_list_userinfo_for_exp_girl = self._execOrderCommon("exp", 0)
            tmp_map_order_key_uid_for_exp_boy, tmp_map_order_key_order_for_exp_boy, tmp_list_userinfo_for_exp_boy = self._execOrderCommon("exp", 1) 
            #魅力排序
            tmp_map_order_key_uid_for_charm_girl, tmp_map_order_key_order_for_charm_girl, tmp_list_userinfo_for_charm_girl = self._execOrderCommon("charm", 0)
            tmp_map_order_key_uid_for_charm_boy, tmp_map_order_key_order_for_charm_boy, tmp_list_userinfo_for_charm_boy = self._execOrderCommon("charm", 1)
            
            a = HallOfFameManager.s_map_order_by_exp_key_uid_girl      #{uid:order}      根据经验排序队列
            b = HallOfFameManager.s_map_order_by_exp_key_uid_boy      #{uid:order}      根据经验排序队列
            c = HallOfFameManager.s_map_order_by_exp_key_order_girl    #{order:userObj}
            d = HallOfFameManager.s_map_order_by_exp_key_order_boy    #{order:userObj}  
            e = HallOfFameManager.s_list_order_by_exp_userinfo_girl 
            f = HallOfFameManager.s_list_order_by_exp_userinfo_boy 
            
            g = HallOfFameManager.s_map_order_by_charm_key_uid_girl      #{uid:order}      根据魅力排序队列
            h = HallOfFameManager.s_map_order_by_charm_key_uid_boy      #{uid:order}      根据魅力排序队列
            i = HallOfFameManager.s_map_order_by_charm_key_order_girl    #{order:userObj}
            j = HallOfFameManager.s_map_order_by_charm_key_order_boy    #{order:userObj}  
            k = HallOfFameManager.s_list_order_by_charm_userinfo_girl 
            l = HallOfFameManager.s_list_order_by_charm_userinfo_boy 
             
            #切换到全局缓存中 
            HallOfFameManager.s_lock.acquire()  #加锁
            try:    
                HallOfFameManager.s_map_order_by_exp_key_uid_girl = tmp_map_order_key_uid_for_exp_girl      #{uid:order}      根据经验排序队列
                HallOfFameManager.s_map_order_by_exp_key_uid_boy = tmp_map_order_key_uid_for_exp_boy     #{uid:order}      根据经验排序队列
                HallOfFameManager.s_map_order_by_exp_key_order_girl = tmp_map_order_key_order_for_exp_girl    #{order:userObj}
                HallOfFameManager.s_map_order_by_exp_key_order_boy = tmp_map_order_key_order_for_exp_boy    #{order:userObj}  
                HallOfFameManager.s_list_order_by_exp_userinfo_girl = tmp_list_userinfo_for_exp_girl
                HallOfFameManager.s_list_order_by_exp_userinfo_boy = tmp_list_userinfo_for_exp_boy
                
                HallOfFameManager.s_map_order_by_charm_key_uid_girl = tmp_map_order_key_uid_for_charm_girl     #{uid:order}      根据魅力排序队列
                HallOfFameManager.s_map_order_by_charm_key_uid_boy = tmp_map_order_key_uid_for_charm_boy      #{uid:order}      根据魅力排序队列
                HallOfFameManager.s_map_order_by_charm_key_order_girl = tmp_map_order_key_order_for_charm_girl    #{order:userObj}
                HallOfFameManager.s_map_order_by_charm_key_order_boy = tmp_map_order_key_order_for_charm_boy    #{order:userObj}  
                HallOfFameManager.s_list_order_by_charm_userinfo_girl = tmp_list_userinfo_for_charm_girl 
                HallOfFameManager.s_list_order_by_charm_userinfo_boy = tmp_list_userinfo_for_charm_boy 
                
                tmpEndTime = time.time()
                tmpDistanceTime = tmpEndTime - tmpBeginTime
                
                self._setTimePreExecNoLock(tmpEndTime)     #设置上一次执行时间为结束时间
                self._setTimeNextExecExtNoLock()           #重新计算下一次执行时间
                
                log.print_debug(logger, "HallOfFameManager execOrder finsih...beginTime[%s], endTime[%s], tmpDistanceTime[%s]" 
                                % (tmpBeginTime, tmpEndTime, tmpDistanceTime))
            finally:
                HallOfFameManager.s_lock.release() #解锁
            del a, b, c, d, e, f, g, h, i, j, k, l
        except Exception:
            log.print_error(logger, 'HallOfFameManager execOrder error:\n%s' % traceback.format_exc())
    
    def _queryUserInfoTuple(self, tmpUIDs, parmsOrderType):
        '''查询DB'''
        if not isinstance(tmpUIDs, list):
            tmpTupleUIDs = "(%s)" % tmpUIDs
        else:
            tmpTupleUIDs = tuple(tmpUIDs)
        
        tmpCols = "a.*, b.*, c.attt_me, c.my_attt, c.hidden_love_me, c.my_hidden_love, c.my_neighbor"
        sql = "SELECT %s FROM t_user AS a, t_user_data AS b, t_user_record AS c \
            WHERE a.uid in %s AND a.uid=b.uid AND a.uid=c.uid %s;" % (tmpCols, tmpTupleUIDs, parmsOrderType)       
        
        conn = mysql()
        return conn.getAll(sql)     
    
    def _formateUserInfo(self, tmpUserInfo): 
        '''格式化'''
        tmpInfoArray = ['my_props_using', 'my_bodyinfo', 'attt_me', 'my_attt', 'hidden_love_me', 'my_hidden_love']
        tmpInfoArray2 = ['birthday', 'regtime', 'last_login_time', 'upload_head_time']
        tmpInfoArray3 = ['reg_step', 'my_neighbor']
    
        util.jsonDecodePerListItemToDict(tmpUserInfo, tmpInfoArray) #把数组info的 项 在数组tmpInfoArray的字段 转换成 字典对象
        util.setPerListItemToStr(tmpUserInfo, tmpInfoArray2)        #把数组info的 项 在数组tmpInfoArray的字段 转换成 字符串
        util.jsonDecodePerListItemToList(tmpUserInfo, tmpInfoArray3) #把数组info的 项 在数组tmpInfoArray的字段 转换成 数组对象

    def queryUserFromDB(self, tmpUID):
        tmpTuple = self._queryUserInfoTuple(tmpUID, "")
        if len(tmpTuple) != 1:
            return None
        
        tmpUserInfo = tmpTuple[0]
        self._formateUserInfo(tmpUserInfo)
        
        tmpTargetUser = User(0, tmpUserInfo, None) #新建一临时用户
        
        import user
        user.UserManager.setUserFriendMapExt(tmpTargetUser, tmpUserInfo)#存到内存
#        tmpTargetUser.setMyFriendMap(tmpInfo.get("my_friend"))  
#        tmpTargetUser.setMyAtttMap(tmpInfo.get("my_attt"))
#        tmpTargetUser.setAtttMeMap(tmpInfo.get("attt_me"))
#        tmpTargetUser.setMyHiddenLoveMap(tmpInfo.get("my_hidden_love"))
#        tmpTargetUser.setHiddenLoveMeMap(tmpInfo.get("hidden_love_me"))
        
        return tmpTargetUser
    
    def _execOrderCommon(self, parmsType="exp", parmsSex=0):
        '''排序'''
        
        tmpDebugTimeDis = 0
        tmpDebugTime = time.time()
        log.print_debug(logger, "_execOrderCommon=======0==select begin-----parmsType[%s] sex[%s]..time:[%s].Timedistince[%s]" % (parmsType, parmsSex, tmpDebugTime, tmpDebugTimeDis))
        
        #查询DB---
        conn = mysql()
        strSql = "SELECT a.uid FROM t_user AS a, t_user_data AS b WHERE a.sex =  '%s' AND a.uid = b.uid \
            ORDER BY b.%s DESC, a.uid ASC;" % (parmsSex, parmsType);
        tmpDBTuple = conn.getAll(strSql)
        
        tmpDebugTimeDis = time.time() - tmpDebugTime
        tmpDebugTime = time.time()
        log.print_debug(logger, "_execOrderCommon=======1==select end-----parmsType[%s] sex[%s]..time:[%s].Timedistince[%s]" % (parmsType, parmsSex, tmpDebugTime, tmpDebugTimeDis))
        
        
        #临时缓存---
        tmp_map_order_uid = {}         #{order:uid}  #前500名的UID
        tmp_list_uids = []             #前500名的UID
        
        tmp_map_order_key_uid = {}     #{uid:order}
        tmp_map_order_key_order = {}   #{order:userObj} 
        tmp_list_userinfo = []         #
        
        #存临时缓存key_uid--- 
        tmpMaxCount = self.getMaxCount() #
        #--获取前500
        tmpList = tmpDBTuple[0:tmpMaxCount]
        tmpOrder = 0 
        for tmpUserInfoDict in tmpList:
            tmpUID = int(tmpUserInfoDict.get('uid', 0)) 
            tmpOrder += 1
            tmp_map_order_uid[tmpOrder] = tmpUID
            tmp_list_uids.append(tmpUID)
                    
        tmpDebugTimeDis = time.time() - tmpDebugTime
        tmpDebugTime = time.time()
        log.print_debug(logger, "_execOrderCommon=======2==存临时缓存key_uid-----parmsType[%s] sex[%s]..time:[%s].Timedistince[%s]" % (parmsType, parmsSex, tmpDebugTime, tmpDebugTimeDis))
        
        #--获取所有
        tmpOrder = 0 
        for tmpUserInfoDict in tmpDBTuple:
            tmpUID = int(tmpUserInfoDict.get('uid', 0))
            tmpOrder += 1
            tmp_map_order_key_uid[tmpUID] = tmpOrder
            
        tmpDebugTimeDis = time.time() - tmpDebugTime
        tmpDebugTime = time.time()
        log.print_debug(logger, "_execOrderCommon=======3==获取所有-----parmsType[%s] sex[%s]..time:[%s].Timedistince[%s]" % (parmsType, parmsSex, tmpDebugTime, tmpDebugTimeDis))
       
        #从临时缓存key_uid中获取前500名--查询其用户信息-存临时缓存key_order
        from bar_order import BarOrderManager
        tmpBarManager = BarOrderManager.instance()     #酒吧名人堂管理对象 
  
        if len(tmp_list_uids) > 0:
            parmsOrderType = "ORDER BY b.%s DESC, a.uid ASC" % parmsType
            info = self._queryUserInfoTuple(tmp_list_uids, parmsOrderType)
            tmpTupleUIDs = tuple(tmp_list_uids)
            
            tmpDebugTimeDis = time.time() - tmpDebugTime
            tmpDebugTime = time.time()
            log.print_debug(logger, "_execOrderCommon=======4==_queryUserInfoTuple-----parmsType[%s] sex[%s]..time:[%s].Timedistince[%s]" % (parmsType, parmsSex, tmpDebugTime, tmpDebugTimeDis))
            
            for tmpUserInfo in info:
                self._formateUserInfo(tmpUserInfo) #格式化信息

                tmpUID = tmpUserInfo.get('uid')
                tmpOrder = tmp_map_order_key_uid.get(tmpUID)

                tmpUser = User(0, tmpUserInfo, None) #新建一临时用户        
                import user
                user.UserManager.setUserFriendMapExt(tmpUser, tmpUserInfo)#存到内存
                
                tmpClientDict = tmpBarManager.getUserInfoToClientForHallOfFame(tmpUser, tmpOrder)
                
                tmp_map_order_key_order[tmpOrder] = tmpClientDict   #存到内存map
                util.inserList(tmp_list_userinfo, tmpClientDict)    #uid保存到内存队列
                
        tmpDebugTimeDis = time.time() - tmpDebugTime
        tmpDebugTime = time.time()
        log.print_debug(logger, "_execOrderCommon=======5==end-----parmsType[%s] sex[%s]..time:[%s].Timedistince[%s]" % (parmsType, parmsSex, tmpDebugTime, tmpDebugTimeDis))
        
        return (tmp_map_order_key_uid, tmp_map_order_key_order, tmp_list_userinfo)
        
        
#---线程名人堂堂排序  
class HallOfFameThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
              
    def run(self):
        try:
            tmpHallOfFameManager = HallOfFameManager.instance()
            while True:
                tmpTimeNextExec = tmpHallOfFameManager.getTimeNextExec() #获取执行时间
                tmpDistanceTime = tmpTimeNextExec - time.time()          #获取剩余时间
                
                if tmpDistanceTime <= 0:
                    log.print_debug(logger, "HallOfFameThread sql exec...begin..time:[%s]." % time.time())
                    tmpHallOfFameManager.execOrder() #执行名人堂排序 
                else:
                    print "\nHallOfFameThread-----sleep----[%s] will execOrder, tmpDistanceTime[%s]\n" %(tmpTimeNextExec, tmpDistanceTime)
                    time.sleep(1)
        except Exception:
            log.print_error(logger, 'HallOfFameThread, run error:\n%s' % traceback.format_exc())

    